/******************************************************************************/
/*!
\file   Renderer.cpp
\author David Seah Seng Chong
\par    email: sengchong.seah\@digipen.edu
\par    DigiPen login: sengchong.seah
\par    Course: GAM200
\date   21/10/2011
\brief
Header file
Graphics Engine

Copyright (C) 2011 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the
prior written consent of DigiPen Institute of Technology is prohibited.
*/
/******************************************************************************/
//#include <vector>
#include "PreCompiledHeader.h"
#include "Renderer.hpp"
#include "Window.hpp"
#include "CustomVertexFormat.hpp"
#include "System.hpp"
#include "Timer.h"



LPDIRECT3DVERTEXBUFFER9 vertexBuffer;
HRESULT hr;



Vertex_UTx vertices1[] = {
	// Front Face (1-2-3-4)
	{ -0.5f, 0.5f, -0.5f, 0.0f, 0.0f},
	{ 0.5f, 0.5f, -0.5f, 1.0f, 0.0f},
	{ -0.5f, -0.5f, -0.5f, 0.0f, 1.0f},
	{ 0.5f, -0.5f, -0.5f, 1.0f, 1.0f }
};

/****************************************************************************/
/*!

Constructor

*/
/****************************************************************************/
Renderer::Renderer()
{
	context = NULL;
	device = NULL;
	m_font = NULL;
}

/****************************************************************************/
/*!

Destructor

*/
/****************************************************************************/
Renderer::~Renderer()
{
	// We release the device and context we've set up,
	//and set the pointers to null for good measure.
	if (device != NULL) { device->Release(); device = NULL; }
	if (context != NULL) { context->Release(); context = NULL; }
}

/****************************************************************************/
/*!

Initialize DirectX9
\param hWnd
Window Handler

\param Width
Width of the client Window

\param Height
Height of the Client Window

*/
/****************************************************************************/
bool Renderer::Initialize(HWND hWnd, int width, int height)
{
	context = Direct3DCreate9(D3D_SDK_VERSION);
	parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
	parameters.BackBufferCount = 1;
	parameters.MultiSampleType = D3DMULTISAMPLE_NONE;
	parameters.MultiSampleQuality = 0;
	parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
	parameters.hDeviceWindow = hWnd;
	parameters.Windowed = true;

	parameters.BackBufferWidth = width;
	parameters.BackBufferHeight = height;

	parameters.EnableAutoDepthStencil = true;
	parameters.AutoDepthStencilFormat = D3DFMT_D16;
	parameters.Flags = NULL;
	parameters.FullScreen_RefreshRateInHz = 0;
	parameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

	if(FAILED(context->CreateDevice(D3DADAPTER_DEFAULT,
		D3DDEVTYPE_HAL,
		hWnd,
		D3DCREATE_HARDWARE_VERTEXPROCESSING,
		&parameters,
		&device)))
	{
		return false;
	}



	// Create the font for drawing text on screen
	m_font = NULL;
	hr = D3DXCreateFont(	device,						//D3D Device
		22,							//Font height
		0,							//Font width
		FW_NORMAL,					//Font Weight
		1,							//MipLevels
		false,						//Italic
		DEFAULT_CHARSET,			//CharSet
		OUT_DEFAULT_PRECIS,			//OutputPrecision
		PROOF_QUALITY,				//Quality
		DEFAULT_PITCH|FF_DONTCARE,  //PitchAndFamily
		"Comics Sans MS",           //pFacename,
		&m_font);					//*ppFont

	InitializeMatrices();



	D3DXCreateTextureFromFile(device,   //Direct3D Device

		"sp.png",       //File Name

		&g_texture);    //Texture handle


	D3DXCreateTextureFromFile(device,   //Direct3D Device

		"asteroid.png",       //File Name

		&	ASteroid_texture);    //Texture handle

	D3DXCreateTextureFromFile(device,   //Direct3D Device

		"sp2.png",       //File Name

		&	g_texture2);    //Texture handle


	D3DXCreateTextureFromFile(device,   //Direct3D Device

		"sp3.png",       //File Name

		&	g_texture3);    //Texture handle


	D3DXCreateTextureFromFile(device,   //Direct3D Device

		"sp4.png",       //File Name

		&	g_texture4);    //Texture handle


	D3DXCreateTextureFromFile(device,   //Direct3D Device

		"fire.png",       //File Name

		&		Bullet_texture);    //Texture handle

	D3DXCreateTextureFromFile(device,   //Direct3D Device

		"background.jpg",       //File Name

		&		Back_texture);    //Texture handle


	D3DXCreateTextureFromFile(device,   //Direct3D Device

		"menubg.jpeg",       //File Name

		&		Menu_texture);    //Texture handle

	
	return true;
}

/****************************************************************************/
/*!

Creates Vertex Buffer

*/
/****************************************************************************/
void Renderer::InitializeResource()
{   
	HRESULT result = device->CreateVertexBuffer(sizeof(vertices1),
		D3DUSAGE_WRITEONLY,
		FVF_Vertex_UTx,
		D3DPOOL_DEFAULT,
		&vertexBuffer,
		NULL);

	void* bufferMemory = 0;
	result = vertexBuffer->Lock(0,
		sizeof(vertices1),
		&bufferMemory,
		NULL);
	memcpy(bufferMemory, vertices1, sizeof(vertices1));
	vertexBuffer->Unlock();

	//Turn off D3D lighting since we are providing our own vertex colors
	device->SetRenderState(D3DRS_LIGHTING, FALSE);

	//enable alpha blending (transparency)
	device->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
	device->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
	device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); 
	device->SetRenderState(D3DRS_ALPHAREF, (DWORD)8); 
	device->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); 
	// Turn on the zbuffer
	device->SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE );
	device->SetRenderState(D3DRS_LIGHTING, false);
	device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
	device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );

}

/****************************************************************************/
/*!

Camera Matrices

*/
/****************************************************************************/
void Renderer::InitializeMatrices()
{
	D3DXVECTOR3 viewVectors[3] = {
		D3DXVECTOR3(0.0f, 0.0f, -1.0f), // i changed this to -1 instead of -10 to test
		D3DXVECTOR3(0.0f, 0.0f, 0.0f),
		D3DXVECTOR3(0.0f, 1.0f, 0.0f)
	};

	SetViewMatrix(viewVectors);

	// The default projection matrix is just fine.
	//SetProjectionMatrix();
	D3DXMATRIX matProjection;
	D3DXMatrixOrthoLH(	&matProjection, static_cast<float>(SYSTEM->GetWindowWidth()),
		static_cast<float>(SYSTEM->GetWindowHeight()), -100, 100);

	device->SetTransform(D3DTS_PROJECTION, &matProjection);    // set the projection
}



//Global Buffer!
Vertex_UD mVertexBuffer[2048][4];

void Renderer::DrawDynamic()
{	

	for(int i = 0; i < 1; ++i )
	{
		mVertexBuffer[i][0].x = -30.5f + i;
		mVertexBuffer[i][0].y = -30.5f + i;
		mVertexBuffer[i][0].z = 0;
		mVertexBuffer[i][0].u = 0.0f;
		mVertexBuffer[i][0].v = 1.0f;
		mVertexBuffer[i][0].color =  0XFFFF0000;

		//top left
		mVertexBuffer[i][1].x = -30.5f+ i;
		mVertexBuffer[i][1].y = 30.5f+ i;
		mVertexBuffer[i][1].z = 0;
		mVertexBuffer[i][1].u = 0.0f;
		mVertexBuffer[i][1].v = 0.0f;
		mVertexBuffer[i][1].color =  0XFFFF0000;

		//bottom right
		mVertexBuffer[i][2].x = 30.5f+ i;
		mVertexBuffer[i][2].y = -30.5f+ i;
		mVertexBuffer[i][2].z = 0;
		mVertexBuffer[i][2].u = 1.0f;
		mVertexBuffer[i][2].v = 1.0f;
		mVertexBuffer[i][2].color = 0XFFFFF00;

		//top right
		mVertexBuffer[i][3].x = 30.5f+ i;
		mVertexBuffer[i][3].y = 30.5f+ i;
		mVertexBuffer[i][3].z = 0;
		mVertexBuffer[i][3].u = 1.0f;
		mVertexBuffer[i][3].v = 0.0f;
		mVertexBuffer[i][3].color = 0XFFFFF00;

	}

	m_VB.CreateBuffer(device,4*2048, FVF_Vertex_UD, sizeof(Vertex_UD),TRUE);
	m_VB.SetData(4*2048,mVertexBuffer, D3DLOCK_DISCARD);

	m_VB.Render(device,2*2048,    D3DPT_TRIANGLESTRIP       );
}

/****************************************************************************/
/*!
Drawing of objects onto screen.

\param Transformation
Transformation Information

\param TextureId
Texture to Draw

\param Alpha
Alpha Blending
*/
/****************************************************************************/
void Renderer::DrawTexture( D3DXMATRIX Transformation )
{
	device->SetFVF(FVF_Vertex_UTx);
	device->SetStreamSource( 0, vertexBuffer, 0, sizeof(Vertex_UTx));

	D3DXMATRIX mat;
	D3DXMatrixIdentity (&mat);
	device->SetTransform ( D3DTS_TEXTURE0 , &mat);


	//Set Texture
	device->SetTexture(0, g_texture);

	device->SetTransform(D3DTS_WORLD, &(Transformation));
	device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
}



void Renderer::DrawAstroid( D3DXMATRIX Transformation )
{
	device->SetFVF(FVF_Vertex_UTx);
	device->SetStreamSource( 0, vertexBuffer, 0, sizeof(Vertex_UTx));

	D3DXMATRIX mat;
	D3DXMatrixIdentity (&mat);
	device->SetTransform ( D3DTS_TEXTURE0 , &mat);

	//Set Texture
	device->SetTexture(0, ASteroid_texture);

	device->SetTransform(D3DTS_WORLD, &(Transformation));
	device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
}


void Renderer::DrawTexture2( D3DXMATRIX Transformation )
{
	device->SetFVF(FVF_Vertex_UTx);
	device->SetStreamSource( 0, vertexBuffer, 0, sizeof(Vertex_UTx));

	D3DXMATRIX mat;
	D3DXMatrixIdentity (&mat);
	device->SetTransform ( D3DTS_TEXTURE0 , &mat);

	//Set Texture
	device->SetTexture(0, g_texture2);

	device->SetTransform(D3DTS_WORLD, &(Transformation));
	device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
}


void Renderer::DrawTexture3( D3DXMATRIX Transformation )
{
	device->SetFVF(FVF_Vertex_UTx);
	device->SetStreamSource( 0, vertexBuffer, 0, sizeof(Vertex_UTx));

	D3DXMATRIX mat;
	D3DXMatrixIdentity (&mat);
	device->SetTransform ( D3DTS_TEXTURE0 , &mat);

	//Set Texture
	device->SetTexture(0, g_texture3);

	device->SetTransform(D3DTS_WORLD, &(Transformation));
	device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
}



void Renderer::DrawTexture4( D3DXMATRIX Transformation )
{
	device->SetFVF(FVF_Vertex_UTx);
	device->SetStreamSource( 0, vertexBuffer, 0, sizeof(Vertex_UTx));

	D3DXMATRIX mat;
	D3DXMatrixIdentity (&mat);
	device->SetTransform ( D3DTS_TEXTURE0 , &mat);

	//Set Texture
	device->SetTexture(0, g_texture4);

	device->SetTransform(D3DTS_WORLD, &(Transformation));
	device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
}




void Renderer::DrawBulletTexture( D3DXMATRIX Transformation )
{
	device->SetFVF(FVF_Vertex_UTx);
	device->SetStreamSource( 0, vertexBuffer, 0, sizeof(Vertex_UTx));

	D3DXMATRIX mat;
	D3DXMatrixIdentity (&mat);
	device->SetTransform ( D3DTS_TEXTURE0 , &mat);

	//Set Texture
	device->SetTexture(0, Bullet_texture);

	device->SetTransform(D3DTS_WORLD, &(Transformation));
	device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
}


void Renderer::DrawBackground( D3DXMATRIX Transformation )
{
	device->SetFVF(FVF_Vertex_UTx);
	device->SetStreamSource( 0, vertexBuffer, 0, sizeof(Vertex_UTx));

	D3DXMATRIX mat;
	D3DXMatrixIdentity (&mat);
	device->SetTransform ( D3DTS_TEXTURE0 , &mat);

	//Set Texture
	device->SetTexture(0, Back_texture);

	device->SetTransform(D3DTS_WORLD, &(Transformation));
	device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
}


void Renderer::DrawMenuBG( )
{
	device->SetFVF(FVF_Vertex_UTx);
	device->SetStreamSource( 0, vertexBuffer, 0, sizeof(Vertex_UTx));

	D3DXMATRIX mat;
	D3DXMatrixIdentity (&mat);
	device->SetTransform ( D3DTS_TEXTURE0 , &mat);

	//Set Texture
	device->SetTexture(0, Menu_texture);

	D3DXMATRIX Transformation;
	D3DXMatrixIdentity (&Transformation);
	D3DXMatrixScaling(&Transformation, 800, 600,1.0f);

	device->SetTransform(D3DTS_WORLD, &(Transformation));
	device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

}



/****************************************************************************/
/*!
Print Text in the Game world

\param str

\param xPos

\param yPos

\param color

\param rectWidth

\param rectHeight
*/
/****************************************************************************/
void Renderer::PrintTextWorld(std::string str, float xPos, float yPos, COLORS color, float rectWidth, float rectHeight)
{
	float scaleX = 1;
	float scaleY = 1;
	xPos *= scaleX;
	yPos *= scaleY;
	rectWidth *= scaleX;
	rectHeight *= scaleY;

	float yDiff = static_cast<float>(SYSTEM->GetWindowHeight() / 2);
	float xDiff = static_cast<float>(SYSTEM->GetWindowWidth() / 2);
	yPos *= -1;
	xPos+= xDiff;
	yPos += yDiff;

	RECT textRect;
	SetRect(&textRect,
		static_cast<int>(xPos),							//xLeft
		static_cast<int>(yPos),							//yTop
		static_cast<int>(xPos + rectWidth),				//xRight
		static_cast<int>(yPos + rectHeight + 0.5f));    //yBottom)

	m_font->DrawText(NULL,							//pSprite - note: draw on sprite makes it faster by up to 4x
		str.c_str(),					//pString
		str.length(),					//Count of chars to render.
		&textRect,						//pRect
		DT_LEFT|DT_NOCLIP|DT_WORDBREAK,	//Format,
		color);							//Color
}



/****************************************************************************/
/*!

Prepare Directx9 to draw

*/
/****************************************************************************/
void Renderer::PrepareToDraw()
{

	device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255, 255, 255/*white*/), 1.0f, 0);
	device->BeginScene();
}

/****************************************************************************/
/*!

Inform DirectX that to End drawing for current Frame

*/
/****************************************************************************/
void Renderer::EndDraw()
{
	//m_line->End();
	device->EndScene();
	hr = device->Present(NULL, NULL, NULL, NULL);
}

/****************************************************************************/
/*!

ReleaseResources

*/
/****************************************************************************/
void Renderer::ReleaseResources()
{

	if (vertexBuffer!= NULL)
	{
		vertexBuffer->Release();
		vertexBuffer = NULL;
	}


	// release resource when done.
	if(m_font != NULL)
	{
		m_font->Release();
		m_font = NULL;
	}

	if(	device != NULL ) // close and release the device memory
	{
		device->Release();
		device = NULL;
	}

	if( context != NULL ) // close and release Direct3D
	{
		context->Release();
		context = NULL;
	}

	if(g_texture != NULL)
	{
		g_texture->Release();
	}

	if(ASteroid_texture != NULL)
	{
		ASteroid_texture->Release();
	}
	if(g_texture2 != NULL)
	{
		g_texture2->Release();
	}
	if(g_texture3 != NULL)
	{
		g_texture3->Release();
	}
	if(g_texture4 != NULL)
	{
		g_texture4->Release();
	}


	if(Bullet_texture != NULL)
	{
		Bullet_texture->Release();
	}
	
	if(Back_texture != NULL)
	{
		Back_texture->Release();
	}
	
	if(Menu_texture != NULL)
	{
		Menu_texture->Release();
	}

}

/****************************************************************************/
/*!

View Matrix

\param eye
Position of the eye. This contains the exact position of the camera.

\param lookat
Position to look at. This vector contains the exact location the camera 
should look at.  

\param up
Position to look up. This vector contains the direction of "up" for the 
camera. In other words, what direction will the top of the screen be. 
Usually, we use the y-axis as the "up" direction.

*/
/****************************************************************************/
void Renderer::SetViewMatrix(const D3DXVECTOR3& eye, const D3DXVECTOR3& lookAt, const D3DXVECTOR3& up)
{
	D3DXMATRIX viewMatrix;
	D3DXMatrixLookAtLH(&viewMatrix, &eye, &lookAt, &up);
	device->SetTransform(D3DTS_VIEW, &viewMatrix);
}


